home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / www / src / WWW / LineMode / Implementation / GridText.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-03  |  24.5 KB  |  1,021 lines

  1. /*        Character grid hypertext object
  2. **        ===============================
  3. */
  4.  
  5. /* Implements:
  6. */
  7. #include "HText.h"
  8.  
  9. #include <assert.h>
  10. #include <ctype.h>
  11. #include "HTUtils.h"
  12. #include "HTString.h"
  13. #include "GridText.h"
  14. #include "HTFont.h"
  15. #include "HTBrowse.h"
  16. #include "HTStream.h"
  17.  
  18.  
  19. struct _HTStream {            /* only know it as object */
  20.     CONST HTStreamClass *    isa;
  21.     /* ... */
  22. };
  23.  
  24. #define MAX_LINE    HTScreenWidth    /* No point in accumulating more */
  25. #ifdef THINK_C
  26. #define LOADED_LIMIT 3            /* For now, save last two texts */
  27. #else
  28. #define LOADED_LIMIT 6            /* For now, save last five texts */
  29. #endif
  30.  
  31. /*    From main program:
  32. */
  33. extern char * reference_mark;        /* Template for anchors */
  34. extern char * end_mark;            /* Template for end */
  35. extern int HTScreenWidth,        /* The screen width */
  36.     HTScreenHeight;            /* The screen height */
  37. extern BOOL display_anchors;        /* anchor will be shown in text? */
  38.     
  39. #ifdef CURSES
  40. #define DISPLAY_LINES (HTScreenHeight)
  41. #define       TITLE_LINES      0
  42. #else
  43. #define DISPLAY_LINES (HTScreenHeight - 1)   /* Exclude prompt line */
  44. #define       TITLE_LINES      1
  45. #endif
  46.  
  47.  
  48. /*    From default style sheet:
  49. */
  50. extern HTStyleSheet * styleSheet;    /* Default or overridden */
  51.  
  52.  
  53. /*    Exports
  54. */ 
  55. PUBLIC HText * HTMainText = 0;        /* Equivalent of main window */
  56. PUBLIC HTParentAnchor * HTMainAnchor = 0;    /* Anchor for HTMainText */
  57.  
  58. typedef struct _line {
  59.     struct _line    *next;
  60.     struct _line    *prev;
  61.     short unsigned    offset;        /* Implicit initial spaces */
  62.     short unsigned    size;        /* Number of characters */
  63.     BOOL    split_after;        /* Can we split after? */
  64.     BOOL    bullet;            /* Do we bullet? */
  65.     char    data[1];        /* Space for terminator at least! */
  66. } HTLine;
  67.  
  68. #define LINE_SIZE(l) (sizeof(HTLine)+(l))    /* allow for terminator */
  69.  
  70. typedef struct _TextAnchor {
  71.     struct _TextAnchor *    next;
  72.     int            number;        /* For user interface */
  73.     int            start;        /* Characters */
  74.     int            extent;        /* Characters */
  75.     HTChildAnchor *        anchor;
  76. } TextAnchor;
  77.  
  78.  
  79. /*    Notes on struct _Htext:
  80. **    next_line is valid iff state is false.
  81. **    top_of_screen line means the line at the top of the screen
  82. **            or just under the title if there is one.
  83. */
  84. struct _HText {
  85.     HTParentAnchor *    node_anchor;
  86.     char *            title;
  87.     HTLine *         last_line;
  88.     int            lines;        /* Number of them */
  89.     int            chars;        /* Number of them */
  90.     TextAnchor *        first_anchor;    /* Singly linked list */
  91.     TextAnchor *        last_anchor;
  92.     int            last_anchor_number;    /* user number */
  93. /* For Internal use: */    
  94.     HTStyle *        style;            /* Current style */
  95.     int            display_on_the_fly;    /* Lines left */
  96.     int            top_of_screen;        /* Line number */
  97.     HTLine *        top_of_screen_line;    /* Top */
  98.     HTLine *        next_line;        /* Bottom + 1 */
  99.     int            permissible_split;    /* in last line */
  100.     BOOL            in_line_1;        /* of paragraph */
  101.     BOOL            stale;            /* Must refresh */
  102.     
  103.     HTStream*        target;            /* Output stream */
  104.     HTStreamClass        targetClass;        /* Output routines */
  105. };
  106.  
  107.  
  108. #define PUTC(c) (*text->targetClass.put_character)(text->target, c)
  109. #define PUTS(s) (*text->targetClass.put_string)(text->target, s)
  110.  
  111. /*    Boring static variable used for moving cursor across
  112. */
  113.  
  114. #define SPACES(n) (&space_string[HTScreenWidth - (n)])
  115.                                    /* String containing blank spaces only */
  116. PRIVATE char * space_string;
  117.  
  118. PRIVATE HTStyle default_style =
  119.     { 0,  "(Unstyled)", "",
  120.     (HTFont)0, 1.0, HT_BLACK,        0, 0,
  121.     0, 0, 0, HT_LEFT,        1, 0,    0, 
  122.     NO, NO, 0, 0,            0 };    
  123.  
  124.  
  125. PUBLIC void clear_screen NOPARAMS;    /* Forward */
  126.  
  127. PRIVATE HTList * loaded_texts;    /* A list of all those in memory */
  128.  
  129. /*            Creation Method
  130. **            ---------------
  131. */
  132. PUBLIC HText *    HText_new ARGS1(HTParentAnchor *,anchor)
  133. {
  134.     HTLine * line;
  135.     HText * self = (HText *) malloc(sizeof(*self));
  136.     if (!self) return self;
  137.     
  138.     if (!loaded_texts) loaded_texts = HTList_new();
  139.     HTList_addObject(loaded_texts, self);
  140.     if (HTList_count(loaded_texts) >= LOADED_LIMIT) {
  141.         if (TRACE) fprintf(stderr, "GridText: Freeing off cached doc.\n"); 
  142.         HText_free((HText *)HTList_removeFirstObject(loaded_texts));
  143.     }
  144.     
  145.     line = self->last_line = (HTLine *)malloc(LINE_SIZE(MAX_LINE));
  146.     if (line == NULL) outofmem(__FILE__, "HText_New");
  147.     line->next = line->prev = line;
  148.     line->offset = line->size = 0;
  149.     self->lines = self->chars = 0;
  150.     self->title = 0;
  151.     self->first_anchor = self->last_anchor = 0;
  152.     self->style = &default_style;
  153.     self->top_of_screen = 0;
  154.     self->node_anchor = anchor;
  155.     self->last_anchor_number = 0;    /* Numbering of them for references */
  156.     self->stale = YES;
  157.     
  158.     self->target = NULL;
  159.     
  160.     HTAnchor_setDocument(anchor, (HyperDoc *)self);
  161.  
  162.     clear_screen();
  163.     HTMainText = self;
  164.     HTMainAnchor = anchor;
  165.     self->display_on_the_fly = DISPLAY_LINES;
  166.     
  167.     if (!space_string) {    /* Make a blank line */
  168.         char *p;
  169.     space_string = (char *)malloc(HTScreenWidth+1);
  170.     if (space_string == NULL) outofmem(__FILE__, "HText_New");
  171.         for (p=space_string; p<space_string+HTScreenWidth; p++) 
  172.             *p = ' ';         /* Used for printfs later */
  173.         space_string[HTScreenWidth] = '\0'; 
  174.     }
  175.     
  176.     return self;
  177. }
  178.  
  179.  
  180. /*            Creation Method 2
  181. **            ---------------
  182. **
  183. **    Stream is assumed open and left open.
  184. */
  185. PUBLIC HText *    HText_new2 ARGS2(
  186.         HTParentAnchor *,    anchor,
  187.         HTStream*,        stream)
  188.  
  189. {
  190.     HText * this = HText_new(anchor);
  191.         
  192.     if (stream) {
  193.         this->target = stream;
  194.     this->targetClass = *stream->isa;    /* copy action procedures */
  195.     }    
  196.     return this;
  197. }
  198.  
  199.  
  200. /*    Free Entire Text
  201. **    ----------------
  202. */
  203. PUBLIC void     HText_free ARGS1(HText *,self)
  204. {
  205.     HTAnchor_setDocument(self->node_anchor, (HyperDoc *)0);
  206.     
  207.     while(YES) {        /* Free off line array */
  208.         HTLine * l = self->last_line;
  209.     l->next->prev = l->prev;
  210.     l->prev->next = l->next;    /* Unlink l */
  211.     self->last_line = l->prev;
  212.     free(l);
  213.     if (l == self->last_line) break;    /* empty */
  214.     };
  215.     
  216.     while(self->first_anchor) {        /* Free off anchor array */
  217.         TextAnchor * l = self->first_anchor;
  218.     self->first_anchor = l->next;
  219.     free(l);
  220.     }
  221.     free(self);
  222. }
  223.  
  224.  
  225. /*        Display Methods
  226. **        ---------------
  227. */
  228. /*    Clear the screen (on screen-mode systems)
  229. **    ----------------
  230. */
  231. PUBLIC void clear_screen NOARGS
  232. {
  233.     if (TRACE) return;     /* in trace mode, don't clear trace away */
  234. #ifdef CURSES
  235.     if (w_text != NULL) {
  236.       wmove(w_text,0,0);
  237.       wclear(w_text);
  238.     }
  239. #else
  240. #ifdef VM
  241. #ifdef NEWLIB
  242.     int newlib_ncmd = 2;
  243.     char newlib_cmd[2][80];
  244.  
  245.     memset(newlib_cmd, ' ', sizeof(newlib_cmd));
  246.     strncpy(newlib_cmd[0], "clear", 5);        /* Clear screen */
  247.     strncpy(newlib_cmd[1], "quit", 4);        /* Leave newlib */
  248.     newlib(newlib_cmd, &newlib_ncmd);        /* Execute command */
  249.     
  250. #else        /* not NEWLIB - real VM */
  251.     system("CLRSCRN");                /* Clear screen */
  252. #endif        /* not NEWLIB */
  253. #else        /* Not VM */
  254.     /* Do nothing */
  255. #endif        /* Not VM */
  256. #endif                /* Not CURSES */
  257.     if (HTMainText) HTMainText->stale = YES;
  258. }
  259.  
  260.  
  261. /*    Output a line
  262. **    -------------
  263. */
  264. PRIVATE void display_line ARGS2(HText *,text, HTLine *,line)
  265. {
  266. #ifdef CURSES
  267.       int     y, x;
  268.  
  269.       waddstr(w_text, SPACES(line->offset));
  270.       waddstr(w_text, line->data);
  271.       getyx(w_text, y, x);
  272.       if (y < DISPLAY_LINES-1) {
  273.               wmove(w_text, ++y, 0);
  274.       }
  275. #else
  276.    if (!text->target)
  277.        printf("%s%s\n", SPACES(line->offset), line->data);
  278.    else {
  279.        PUTS(SPACES(line->offset));
  280.        PUTS(line->data);
  281.        PUTC('\n');
  282.    }
  283. #endif
  284.    
  285. }
  286.  
  287. /*    Output the title line
  288. **    ---------------------
  289. */
  290. PRIVATE void display_title ARGS1(HText *,text)
  291. {
  292.     CONST char * title = HTAnchor_title(text->node_anchor);
  293.     char percent[20], format[20];
  294.     if (text->lines > (DISPLAY_LINES-1)) {
  295. #ifdef NOPE
  296.     sprintf(percent, " (p%d of %d)",
  297.         (text->top_of_screen/(DISPLAY_LINES-1)) + 1,
  298.         (text->lines-1)/(DISPLAY_LINES-1) + 1);
  299.     sprintf(percent, " (%d%%)",
  300.         100*(text->top_of_screen+DISPLAY_LINES-1)/    /* Seen */
  301.             (text->lines));                /* Total */
  302. #else
  303.     sprintf(percent, " (%d/%d)",
  304.         text->top_of_screen+DISPLAY_LINES-1,    /* Seen */
  305.         text->lines);                /* Total */
  306. #endif
  307.     } else {
  308.     percent[0] = 0;    /* Null string */
  309.     }
  310.  
  311.     sprintf(format, "%%%d.%ds%%s\n",    /* Generate format string */
  312.             (int)(HTScreenWidth-strlen(percent)),
  313.             (int)(HTScreenWidth-strlen(percent)) );
  314. /*    if (TRACE) fprintf(stderr, "FORMAT IS `%s'\n", format);  */
  315. #ifdef CURSES
  316.     mvwprintw(w_top, 0, 0, format, title, percent);
  317.     wrefresh(w_top);
  318. #else
  319.     if (!text->target) printf(format, title, percent);
  320.     else {
  321.         char * line = (char*)malloc(HTScreenWidth+10);
  322.         sprintf(line, format, title, percent);
  323.     PUTS(line);
  324.     free(line);
  325.     }
  326. #endif
  327. }
  328.  
  329.  
  330. /*    Fill the screen with blank after the file
  331. **    --------------------------
  332. */
  333. PRIVATE void fill_screen ARGS2(HText *, text, int,n)
  334. {
  335.     if (n<=0 || n>1000) return;        /* Large value means no pagination */
  336.     if (text->target) return;
  337. #ifdef CURSES
  338.     waddstr(w_text, end_mark);
  339.     wclrtobot(w_text);
  340.     wrefresh(w_text);
  341. #else
  342. #ifndef VIOLA    
  343.     if (!text->target) printf("%s\n", end_mark);
  344.     else { PUTS(end_mark); PUTC('\n'); }
  345.     n--;
  346.     
  347.     for (; n; n--) {
  348.         if (!text->target) printf("\n");
  349.     else PUTC('\n');
  350.     }
  351. #endif
  352. #endif        /* Not CURSES */
  353. }
  354.  
  355.  
  356. /*    Output a page
  357. **    -------------
  358. */
  359. PRIVATE void display_page ARGS2(HText *,text, int,line_number)
  360. {
  361.     HTLine * line = text->last_line->prev;
  362.     int i;
  363.     CONST char * title = HTAnchor_title(text->node_anchor);
  364.     int lines_of_text = title ? (DISPLAY_LINES-TITLE_LINES) : DISPLAY_LINES;
  365.     int last_screen = text->lines - lines_of_text;
  366.  
  367. /*    Constrain the line number to be within the document
  368. */
  369.     if (text->lines <= lines_of_text) line_number = 0;
  370.     else if (line_number>last_screen) line_number = last_screen;
  371.     else if (line_number < 0) line_number = 0;
  372.     
  373.     for(i=0,  line = text->last_line->next;        /* Find line */
  374.         i<line_number && (line!=text->last_line);
  375.       i++, line=line->next) /* Loop */ assert(line->next != NULL);
  376.  
  377.     while((line!=text->last_line) && (line->size==0)) {    /* Skip blank lines */
  378.         assert(line->next != NULL);
  379.       line = line->next;
  380.         line_number ++;
  381.     }
  382.  
  383. /*    Can we just scroll to it?
  384. */ 
  385. #ifndef VM            /* No scrolling */
  386.     if (!text->stale && (line_number>=text->top_of_screen) &&
  387.         (line_number < text->top_of_screen + DISPLAY_LINES)) {    /* Yes */
  388.     lines_of_text = line_number - text->top_of_screen;
  389.     line = text->next_line;
  390.         text->top_of_screen = line_number;
  391. #ifdef CURSES
  392.         scrollok(w_text, TRUE);
  393.         for (i = 0; i < lines_of_text; i++) {
  394.               scroll(w_text);
  395.         }
  396. #endif  
  397.     } else
  398. #endif
  399.     {
  400.     clear_screen();                        /* No */
  401.         text->top_of_screen = line_number;
  402.     if (title) display_title(text);
  403.     }
  404.     
  405. /* Bug: when we scroll to a part slightly futher down a page which previously
  406.  fitted all on one screen including the [End], the code below will add an
  407.  extra [End] to the screen, giving a total of two, one underneath the other.
  408. */
  409.     
  410.  /*    print it
  411.  */
  412.     if (line) {
  413.       for(i=0;
  414.       (i< lines_of_text) && (line != text->last_line); i++)  {
  415.       assert(line != NULL);
  416.         display_line(text, line);
  417.     line = line->next;
  418.       }
  419.       fill_screen(text, lines_of_text - i);
  420.     }
  421.  
  422.     text->next_line = line;    /* Line after screen */
  423.     text->stale = NO;        /* Display is up-to-date */
  424. }
  425.  
  426.  
  427. /*            Object Building methods
  428. **            -----------------------
  429. **
  430. **    These are used by a parser to build the text in an object
  431. */
  432. PUBLIC void HText_beginAppend ARGS1(HText *,text)
  433. {
  434.     text->permissible_split = 0;
  435.     text->in_line_1 = YES;
  436. }
  437.  
  438.  
  439. /*    Add a new line of text
  440. **    ----------------------
  441. **
  442. ** On entry,
  443. **
  444. **    split    is zero for newline function, else number of characters
  445. **        before split.
  446. **    text->display_on_the_fly
  447. **        may be set to indicate direct output of the finished line.
  448. ** On exit,
  449. **        A new line has been made, justified according to the
  450. **        current style. Text after the split (if split nonzero)
  451. **        is taken over onto the next line.
  452. **
  453. **        If display_on_the_fly is set, then it is decremented and
  454. **        the finished line is displayed.
  455. */
  456. #define new_line(text) split_line(text, 0)
  457.  
  458. PRIVATE void split_line ARGS2(HText *,text, int,split)
  459. {
  460.     HTStyle * style = text->style;
  461.     int spare;
  462.     int indent = text->in_line_1 ? text->style->indent1st
  463.                      : text->style->leftIndent;
  464.     
  465. /*    Make new line
  466. */
  467.     HTLine * previous = text->last_line;
  468.     HTLine * line = (HTLine *) malloc(LINE_SIZE(MAX_LINE));
  469.     
  470.     if (line == NULL) outofmem(__FILE__, "split_line");
  471.     text->lines++;
  472.     
  473.     previous->next->prev = line;
  474.     line->prev = previous;
  475.     line->next = previous->next;
  476.     previous->next = line;
  477.     text->last_line = line;
  478.     line->size = 0;
  479.     line->offset = 0;
  480.  
  481. /*    Split at required point
  482. */    
  483.     if (split) {    /* Delete space at "split" splitting line */
  484.     char * p;
  485.     previous->data[previous->size] = 0;
  486.     for (p = &previous->data[split]; *p; p++)
  487.         if (*p != ' ') break;
  488.     strcpy(line->data, p);
  489.     line->size = strlen(line->data);
  490.     previous->size = split;
  491.     }
  492.     
  493. /*    Economise on space.
  494. **    Not on the RS6000 due to a chaotic bug in realloc argument passing.
  495. **    Same problem with Ultrix (4.2) : realloc() is not declared properly.
  496. */
  497. #ifndef AIX
  498. #ifndef ultrix
  499.     while ((previous->size > 0) &&
  500.         (previous->data[previous->size-1] == ' '))    /* Strip trailers */
  501.         previous->size--;
  502.     
  503.     previous = (HTLine *) realloc (previous, LINE_SIZE(previous->size));
  504.     if (previous == NULL) outofmem(__FILE__, "split_line");
  505. #endif /* ultrix */
  506. #endif /* AIX */
  507.  
  508.     previous->prev->next = previous;    /* Link in new line */
  509.     previous->next->prev = previous;    /* Could be same node of course */
  510.  
  511. /*    Terminate finished line for printing
  512. */
  513.     previous->data[previous->size] = 0;
  514.      
  515.     
  516. /*    Align left, right or center
  517. */
  518.  
  519.     spare =  HTScreenWidth -
  520.             style->rightIndent + style->leftIndent -
  521.             previous->size;    /* @@ first line indent */
  522.         
  523.     switch (style->alignment) {
  524.     case HT_CENTER :
  525.         previous->offset = previous->offset + indent + spare/2;
  526.         break;
  527.     case HT_RIGHT :
  528.         previous->offset = previous->offset + indent + spare;
  529.         break;
  530.     case HT_LEFT :
  531.     case HT_JUSTIFY :        /* Not implemented */
  532.     default:
  533.         previous->offset = previous->offset + indent;
  534.         break;
  535.     } /* switch */
  536.  
  537.     text->chars = text->chars + previous->size + 1;    /* 1 for the line */
  538.     text->in_line_1 = NO;        /* unless caller sets it otherwise */
  539.     
  540. /*    If displaying as we go, output it:
  541. */
  542.     if (text->display_on_the_fly) {
  543.         if (text->display_on_the_fly == DISPLAY_LINES) { /* First line */
  544.         if (previous->size == 0) {
  545.             text->top_of_screen++;    /* Scroll white space off top */
  546.         return;
  547.         }
  548.         if (HTAnchor_title(text->node_anchor)) { /* Title exists */
  549.             display_title(text);
  550.             text->display_on_the_fly--;
  551.         }
  552.     }
  553.     display_line(text, previous);
  554.     text->display_on_the_fly--;
  555.     }
  556. } /* split_line */
  557.  
  558.  
  559. /*    Allow vertical blank space
  560. **    --------------------------
  561. */
  562. PRIVATE void blank_lines ARGS2(HText *,text, int,newlines)
  563. {
  564.     if (text->last_line->size == 0) {    /* No text on current line */
  565.     HTLine * line = text->last_line->prev;
  566.     while ((line!=text->last_line) && (line->size == 0)) {
  567.         if (newlines==0) break;
  568.         newlines--;        /* Don't bother: already blank */
  569.         line = line->prev;
  570.     }
  571.     } else {
  572.     newlines++;            /* Need also to finish this line */
  573.     }
  574.  
  575.     for(;newlines;newlines--) {
  576.     new_line(text);
  577.     }
  578.     text->in_line_1 = YES;
  579. }
  580.  
  581.  
  582. /*    New paragraph in current style
  583. **    ------------------------------
  584. ** See also: setStyle.
  585. */
  586.  
  587. PUBLIC void HText_appendParagraph ARGS1(HText *,text)
  588. {
  589.     int after = text->style->spaceAfter;
  590.     int before = text->style->spaceBefore;
  591.     blank_lines(text, after>before ? after : before);
  592. }
  593.  
  594.  
  595. /*    Set Style
  596. **    ---------
  597. **
  598. **    Does not filter unnecessary style changes.
  599. */
  600. PUBLIC void HText_setStyle ARGS2(HText *,text, HTStyle *,style)
  601. {
  602.     int after, before;
  603.  
  604.     if (!style) return;                /* Safety */
  605.     after = text->style->spaceAfter;
  606.     before = style->spaceBefore;
  607.     if (TRACE) fprintf(stderr, "HTML: Change to style %s\n", style->name);
  608.  
  609.     blank_lines (text, after>before ? after : before);
  610.  
  611.     text->style = style;
  612. }
  613.  
  614.  
  615. /*    Append a character to the text object
  616. **    -------------------------------------
  617. */
  618. PUBLIC void HText_appendCharacter ARGS2(HText *,text, char,ch)
  619. {
  620.     HTLine * line = text->last_line;
  621.     HTStyle * style = text->style;
  622.     int indent = text->in_line_1 ? style->indent1st : style->leftIndent;
  623.     
  624. /*        New Line
  625. */
  626.     if (ch == '\n') {
  627.         new_line(text);
  628.         text->in_line_1 = YES;    /* First line of new paragraph */
  629.         return;
  630.     }
  631.  
  632. /*         Tabs
  633. */
  634.  
  635.     if (ch == '\t') {
  636.         HTTabStop * tab;
  637.     int target;    /* Where to tab to */
  638.     int here = line->size + line->offset +indent;
  639.         if (style->tabs) {    /* Use tab table */
  640.         for (tab = style->tabs;
  641.             tab->position <= here;
  642.         tab++)
  643.         if (!tab->position) {
  644.             new_line(text);
  645.             return;
  646.         }
  647.         target = tab->position;
  648.     } else if (text->in_line_1) {    /* Use 2nd indent */
  649.         if (here >= style->leftIndent) {
  650.             new_line(text); /* wrap */
  651.         return;
  652.         } else {
  653.             target = style->leftIndent;
  654.         }
  655.     } else {        /* Default tabs align with left indent mod 8 */
  656. #ifdef DEFAULT_TABS_8
  657.         target = ((line->offset + line->size + 8) & (-8))
  658.                 + style->leftIndent;
  659. #else
  660.         new_line(text);
  661.         return;
  662. #endif
  663.     }
  664.     if (target > HTScreenWidth - style->rightIndent) {
  665.         new_line(text);
  666.         return;
  667.     } else {
  668.             text->permissible_split = line->size;    /* Can split here */
  669.         if (line->size == 0) line->offset = line->offset + target - here;
  670.         else for(; here<target; here++) {
  671.                 line->data[line->size++] = ' ';    /* Put character into line */
  672.         }
  673.         return;
  674.     }
  675.     /*NOTREACHED*/
  676.     } /* if tab */ 
  677.  
  678.     
  679.     if (ch==' ') {
  680.         text->permissible_split = line->size;    /* Can split here */
  681.     }
  682.  
  683. /*    Check for end of line
  684. */    
  685.     if (indent + line->offset + line->size + style->rightIndent
  686.             >= HTScreenWidth) {
  687.         if (style->wordWrap) {
  688.         split_line(text, text->permissible_split);
  689.         if (ch==' ') return;    /* Ignore space causing split */
  690.     } else new_line(text);
  691.     }
  692.  
  693. /*    Insert normal characters
  694. */
  695.     if (ch == HT_NON_BREAK_SPACE) {
  696.         ch = ' ';
  697.     }
  698.     {
  699.         HTLine * line = text->last_line;    /* May have changed */
  700.         HTFont font = style->font;
  701.         line->data[line->size++] =    /* Put character into line */
  702.            font & HT_CAPITALS ? TOUPPER(ch) : ch;
  703.         if (font & HT_DOUBLE)        /* Do again if doubled */
  704.             HText_appendCharacter(text, HT_NON_BREAK_SPACE);
  705.         /* NOT a permissible split */ 
  706.     }
  707. }
  708.  
  709. /*        Anchor handling
  710. **        ---------------
  711. */
  712. /*    Start an anchor field
  713. */
  714. PUBLIC void HText_beginAnchor ARGS2(HText *,text, HTChildAnchor *,anc)
  715. {
  716.     TextAnchor * a = (TextAnchor *) malloc(sizeof(*a));
  717.     
  718.     if (a == NULL) outofmem(__FILE__, "HText_beginAnchor");
  719.     a->start = text->chars + text->last_line->size;
  720.     a->extent = 0;
  721.     if (text->last_anchor) {
  722.         text->last_anchor->next = a;
  723.     } else {
  724.         text->first_anchor = a;
  725.     }
  726.     a->next = 0;
  727.     a->anchor = anc;
  728.     text->last_anchor = a;
  729.     
  730.     if (HTAnchor_followMainLink((HTAnchor*)anc)) {
  731.         a->number = ++(text->last_anchor_number);
  732.     } else {
  733.         a->number = 0;
  734.     }
  735. }
  736.  
  737.  
  738. PUBLIC void HText_endAnchor ARGS1(HText *,text)
  739. {
  740.     TextAnchor * a = text->last_anchor;
  741.     char marker[100];
  742.     if (a->number && display_anchors) {     /* If it goes somewhere */
  743.     sprintf(marker, reference_mark, a->number);
  744.     HText_appendText(text, marker);
  745.     }
  746.     a->extent = text->chars + text->last_line->size - a->start;
  747. }
  748.  
  749.  
  750. PUBLIC void HText_appendText ARGS2(HText *,text, CONST char *,str)
  751. {
  752.     CONST char * p;
  753.     for(p=str; *p; p++) {
  754.         HText_appendCharacter(text, *p);
  755.     }
  756. }
  757.  
  758.  
  759. PUBLIC void HText_endAppend ARGS1(HText *,text)
  760. {
  761.     new_line(text);
  762.     
  763.     if (text->display_on_the_fly) {        /* Not finished? */
  764.         fill_screen(text, text->display_on_the_fly);    /* Finish it */
  765.     text->display_on_the_fly = 0;
  766.     text->next_line = text->last_line;    /* Bug fix after EvA 920117 */
  767.     text->stale = NO;
  768.     }
  769. }
  770.  
  771.  
  772.  
  773. /*     Dump diagnostics to stderr
  774. */
  775. PUBLIC void HText_dump ARGS1(HText *,text)
  776. {
  777.     fprintf(stderr, "HText: Dump called\n");
  778. }
  779.     
  780.  
  781. /*    Return the anchor associated with this node
  782. */
  783. PUBLIC HTParentAnchor * HText_nodeAnchor ARGS1(HText *,text)
  784. {
  785.     return text->node_anchor;
  786. }
  787.  
  788. /*                GridText specials
  789. **                =================
  790. */
  791. /*    Return the anchor with index N
  792. **
  793. **    The index corresponds to the number we print in the anchor.
  794. */
  795. PUBLIC HTChildAnchor * HText_childNumber ARGS2(HText *,text, int,number)
  796. {
  797.     TextAnchor * a;
  798.     for (a = text->first_anchor; a; a = a->next) {
  799.         if (a->number == number) return a->anchor;
  800.     }
  801.     return (HTChildAnchor *)0;    /* Fail */
  802. }
  803.  
  804. PUBLIC void HText_setStale ARGS1(HText *,text)
  805. {
  806.     text->stale = YES;
  807. }
  808.  
  809. PUBLIC void HText_refresh ARGS1(HText *,text)
  810. {
  811.     if (text->stale) display_page(text, text->top_of_screen);
  812. }
  813.  
  814. PUBLIC int HText_sourceAnchors ARGS1(HText *,text)
  815. {
  816.     return text->last_anchor_number;
  817. }
  818.  
  819. PUBLIC BOOL HText_canScrollUp ARGS1(HText *,text)
  820. {
  821.     return text->top_of_screen != 0;
  822. }
  823.  
  824. PUBLIC BOOL HText_canScrollDown ARGS1(HText *,text)
  825. {
  826.     char * title = text->title;
  827.     return (text->top_of_screen + DISPLAY_LINES - (title? TITLE_LINES:0) ) <
  828.             text->lines;
  829. }
  830.  
  831. /*        Scroll actions
  832. */
  833. PUBLIC void HText_scrollTop ARGS1(HText *,text)
  834. {
  835.     display_page(text, 0);
  836. }
  837.  
  838. PUBLIC void HText_scrollDown ARGS1(HText *,text)
  839. {
  840.     display_page(text, text->top_of_screen + DISPLAY_LINES -1);
  841. }
  842.  
  843. PUBLIC void HText_scrollUp ARGS1(HText *,text)
  844. {
  845.     display_page(text, text->top_of_screen - DISPLAY_LINES +1);
  846. }
  847.  
  848. PUBLIC void HText_scrollBottom ARGS1(HText *,text)
  849. {
  850.     display_page(text, text->lines - DISPLAY_LINES +1);
  851. }
  852.  
  853.  
  854. /*        Browsing functions
  855. **        ==================
  856. */
  857.  
  858. /* Bring to front and highlight it
  859. */
  860.  
  861. PRIVATE int line_for_char ARGS2(HText *,text, int,char_num)
  862. {
  863.     int line_number =0;
  864.     int characters = 0;
  865.     HTLine * line = text->last_line->next;
  866.     for(;;) {
  867.     if (line == text->last_line) return 0;    /* Invalid */
  868.         characters = characters + line->size + 1;
  869.     if (characters > char_num) return line_number;
  870.     line_number ++;
  871.     line = line->next;
  872.     }
  873. }
  874.  
  875. PUBLIC BOOL HText_select ARGS1(HText *,text)
  876. {
  877. /*    if (text != HTMainText) {      Do it anyway to refresh */
  878.     {                
  879.         HTMainText = text;
  880.     HTMainAnchor = text->node_anchor;
  881.     display_page(text, text->top_of_screen);
  882.     }
  883.     return YES;
  884. }
  885.  
  886. PUBLIC BOOL HText_selectAnchor ARGS2(HText *,text, HTChildAnchor *,anchor)
  887. {
  888.     TextAnchor * a;
  889.  
  890. /* This is done later, hence HText_select is unused in GridText.c
  891.    Should it be the contrary ? @@@
  892.     if (text != HTMainText) {
  893.         HText_select(text);
  894.     }
  895. */
  896.  
  897.     for(a=text->first_anchor; a; a=a->next) {
  898.         if (a->anchor == anchor) break;
  899.     }
  900.     if (!a) {
  901.         if (TRACE) fprintf(stderr, "HText: No such anchor in this text!\n");
  902.         return NO;
  903.     }
  904.  
  905.     if (text != HTMainText) {        /* Comment out by ??? */
  906.         HTMainText = text;        /* Put back in by tbl 921208 */
  907.     HTMainAnchor = text->node_anchor;
  908.     }
  909.  
  910.     {
  911.      int l = line_for_char(text, a->start);
  912.     if (TRACE) fprintf(stderr,
  913.         "HText: Selecting anchor [%d] at character %d, line %d\n",
  914.         a->number, a->start, l);
  915.  
  916.     if ( !text->stale &&
  917.          (l >= text->top_of_screen) &&
  918.          ( l < text->top_of_screen + DISPLAY_LINES-1))
  919.              return YES;
  920.  
  921.         display_page(text, l - (DISPLAY_LINES/3));    /* Scroll to it */
  922.     }
  923.     
  924.     return YES;
  925. }
  926.  
  927.  
  928. /*        Editing functions        - NOT IMPLEMENTED
  929. **        =================
  930. **
  931. **    These are called from the application. There are many more functions
  932. **    not included here from the orginal text object.
  933. */
  934.  
  935. /*    Style handling:
  936. */
  937. /*    Apply this style to the selection
  938. */
  939. PUBLIC void HText_applyStyle ARGS2(HText *, me, HTStyle *,style)
  940. {
  941.     
  942. }
  943.  
  944.  
  945. /*    Update all text with changed style.
  946. */
  947. PUBLIC void HText_updateStyle ARGS2(HText *, me, HTStyle *,style)
  948. {
  949.     
  950. }
  951.  
  952.  
  953. /*    Return style of  selection
  954. */
  955. PUBLIC HTStyle * HText_selectionStyle ARGS2(
  956.     HText *,me,
  957.     HTStyleSheet *,sheet)
  958. {
  959.     return 0;
  960. }
  961.  
  962.  
  963. /*    Paste in styled text
  964. */
  965. PUBLIC void HText_replaceSel ARGS3(
  966.     HText *,me,
  967.     CONST char *,aString, 
  968.     HTStyle *,aStyle)
  969. {
  970. }
  971.  
  972.  
  973. /*    Apply this style to the selection and all similarly formatted text
  974. **    (style recovery only)
  975. */
  976. PUBLIC void HTextApplyToSimilar ARGS2(HText *,me, HTStyle *,style)
  977. {
  978.     
  979. }
  980.  
  981.  
  982. /*    Select the first unstyled run.
  983. **    (style recovery only)
  984. */
  985. PUBLIC void HTextSelectUnstyled ARGS2(HText *,me, HTStyleSheet *,sheet)
  986. {
  987.     
  988. }
  989.  
  990.  
  991. /*    Anchor handling:
  992. */
  993. PUBLIC void        HText_unlinkSelection ARGS1(HText *,me)
  994. {
  995.     
  996. }
  997.  
  998. PUBLIC HTAnchor *    HText_referenceSelected ARGS1(HText *,me)
  999. {
  1000.      return 0;   
  1001. }
  1002.  
  1003.  
  1004. #ifdef CURSES
  1005. PUBLIC int HText_getTopOfScreen ARGS1(HText *,text)
  1006. {
  1007.       return text->top_of_screen;
  1008. }
  1009.  
  1010. PUBLIC int HText_getLines ARGS1(HText *,text)
  1011. {
  1012.       return text->lines;
  1013. }
  1014. #endif
  1015. PUBLIC HTAnchor *    HText_linkSelTo ARGS2(HText *,me, HTAnchor *,anchor)
  1016. {
  1017.     return 0;
  1018. }
  1019.  
  1020.  
  1021.